package com.mxq.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.net.InetSocketAddress;

/**
 * @author xiaoqiang
 * @Description 引导服务器
 * 文档地址： https://waylau.com/essential-netty-in-action
 * 服务器的主代码组件是
 *
 * EchoServerHandler 实现了的业务逻辑
 * 在 main() 方法，引导了服务器
 * 执行后者所需的步骤是：
 *
 * 创建 ServerBootstrap 实例来引导服务器并随后绑定
 * 创建并分配一个 NioEventLoopGroup 实例来处理事件的处理，如接受新的连接和读/写数据。
 * 指定本地 InertSocketAddress 给服务器绑定
 * 通过 EchoServerHandler 实例给每一个新的 Channel 初始化
 * 最后调用 ServerBootstrap.bind() 绑定服务器
 * @date 2019/8/27 18:24
 */
public class EchoServer {
    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }
    public static void main(String[] args) throws Exception {

        // 1. 设置端口值
        int port = Integer.parseInt("8888");
        // 2. 调用服务器的star方法
        new EchoServer(port).start();
    }

    public void start() throws Exception {

        // 3. 创建EventLoopGroup
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            // 4. 创建ServerBootstrap
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)
                    // 5. 指定使用NIO的传输channel
                    .channel(NioServerSocketChannel.class)
                    // 6. 设置socket地址使用所选的端口
                    .localAddress(new InetSocketAddress(port))
                    // 7. 添加EchoServerHandler到Channel的Pipeline
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch)
                                throws Exception {
                            ch.pipeline().addLast(
                                    new EchoServerHandler());
                        }
                    });
            // 8. 绑定服务器;sync 等待服务器关闭
            ChannelFuture f = b.bind().sync();
            System.out.println(EchoServer.class.getName() + " started and listen on " + f.channel().localAddress());
            // 9. 关闭channel和块，直到它被关闭
            f.channel().closeFuture().sync();
        } finally {
            // 10. 关闭EventLoopGroup,直到它被关闭
            group.shutdownGracefully().sync();
        }
    }
}
